home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 3: Developer Tools / Linux Cubed Series 3 - Developer Tools.iso / devel / lang / ada / gnat-3.05- / gnat-3 / gnat-3.05-i486-linux-elf-bin / rts / 2sinterr.adb < prev    next >
Encoding:
Text File  |  1996-06-07  |  32.0 KB  |  955 lines

  1. ------------------------------------------------------------------------------
  2. --                                                                          --
  3. --                 GNU ADA RUNTIME LIBRARY (GNARL) COMPONENTS               --
  4. --                                                                          --
  5. --                     S Y S T E M . I N T E R R U P T S                    --
  6. --                                                                          --
  7. --                                  B o d y                                 --
  8. --                                                                          --
  9. --                             $Revision: 1.12 $                            --
  10. --                                                                          --
  11. --   Copyright (C) 1991,1992,1993,1994,1995,1996 Florida State University   --
  12. --                                                                          --
  13. -- GNARL is free software; you can  redistribute it  and/or modify it under --
  14. -- terms of the  GNU General Public License as published  by the Free Soft- --
  15. -- ware  Foundation;  either version 2,  or (at your option) any later ver- --
  16. -- sion. GNARL is distributed in the hope that it will be useful, but WITH- --
  17. -- OUT ANY WARRANTY;  without even the  implied warranty of MERCHANTABILITY --
  18. -- or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License --
  19. -- for  more details.  You should have  received  a copy of the GNU General --
  20. -- Public License  distributed with GNARL; see file COPYING.  If not, write --
  21. -- to  the Free Software Foundation,  59 Temple Place - Suite 330,  Boston, --
  22. -- MA 02111-1307, USA.                                                      --
  23. --                                                                          --
  24. -- As a special exception,  if other files  instantiate  generics from this --
  25. -- unit, or you link  this unit with other files  to produce an executable, --
  26. -- this  unit  does not  by itself cause  the resulting  executable  to  be --
  27. -- covered  by the  GNU  General  Public  License.  This exception does not --
  28. -- however invalidate  any other reasons why  the executable file  might be --
  29. -- covered by the  GNU Public License.                                      --
  30. --                                                                          --
  31. -- GNARL was developed by the GNARL team at Florida State University. It is --
  32. -- now maintained by Ada Core Technologies Inc. in cooperation with Florida --
  33. -- State University (http://www.gnat.com).                                  --
  34. --                                                                          --
  35. ------------------------------------------------------------------------------
  36.  
  37. --  This implemetation is targeted for 9X-Runtime build upon
  38. --  Solaris 2.3 thread library.
  39.  
  40. with Ada.Interrupts.Names; use Ada.Interrupts.Names;
  41. with Ada.Interrupts; use Ada.Interrupts;
  42.  
  43. with System.Storage_Elements;
  44. with Interfaces.C.POSIX_RTE;
  45. with Interfaces.C.POSIX_Error;
  46. with Interfaces.C.Sthreads;
  47. with System.Task_Primitives; use System.Task_Primitives;
  48. with System.Tasking; use System.Tasking;
  49. with System.Tasking.Rendezvous;
  50. with System.Tasking.Utilities;
  51. with System.Error_Reporting; use System.Error_Reporting;
  52. with Unchecked_Conversion;
  53.  
  54. package body System.Interrupts is
  55.    package RTE renames Interfaces.C.POSIX_RTE;
  56.  
  57.    package POSIX_Error renames Interfaces.C.POSIX_Error;
  58.    use type POSIX_Error.Return_Code;
  59.  
  60.    package Utilities renames System.Tasking.Utilities;
  61.  
  62.    Failure : Interfaces.C.POSIX_Error.Return_Code
  63.       renames Interfaces.C.POSIX_Error.Failure;
  64.  
  65.    --  Locks and Cond variables for each Interrupt
  66.  
  67.    M : array (Ada.Interrupts.Interrupt_ID'Range) of Lock;
  68.  
  69.    C : array (Ada.Interrupts.Interrupt_ID'Range) of Condition_Variable;
  70.  
  71.    --  Interrupts to which a Handler or an Entry can be bound
  72.    Usable_Interrupts : array (Ada.Interrupts.Interrupt_ID'Range) of Boolean;
  73.  
  74.    type Handler_Assoc is record
  75.       H      : Ada.Interrupts.Parameterless_Handler;
  76.       Static : Boolean;   --  Indicates static binding;
  77.    end record;
  78.  
  79.    Null_Handler_Assoc : constant Handler_Assoc := Handler_Assoc'
  80.      (H => null, Static => false);
  81.  
  82.    --  Table to maintain current Interrupt Handler binding
  83.    User_Handlers :
  84.      array (Ada.Interrupts.Interrupt_ID'Range) of Handler_Assoc
  85.        := (others => Null_Handler_Assoc);
  86.  
  87.    type Entry_Assoc is record
  88.       T : Tasking.Task_ID;
  89.       E : Tasking.Task_Entry_Index;
  90.    end record;
  91.  
  92.    Null_Entry_Assoc : constant Entry_Assoc := Entry_Assoc'
  93.      (T => Tasking.Null_Task, E => Tasking.Null_Task_Entry);
  94.  
  95.    --  Table to maintain current Interrupt Entry binding
  96.    User_Entries : array (Ada.Interrupts.Interrupt_ID'Range) of Entry_Assoc
  97.      := (others => Null_Entry_Assoc);
  98.  
  99.    --  Table to maintain Task_ID of Handler_Task for each Interrupts.
  100.    Handler_Task_IDs :
  101.      array (Ada.Interrupts.Interrupt_ID'Range) of System.Tasking.Task_ID
  102.        := (others => System.Tasking.Null_Task);
  103.  
  104.    --  Table to maintain the information if a signal is blocked.
  105.    Status_Blocked :
  106.      array (Ada.Interrupts.Interrupt_ID'Range) of Boolean
  107.        := (others => false);
  108.  
  109.    --  Type and Head, Tail of the list containing Registered Interrupt
  110.    --  Handlers.
  111.  
  112.    type Registered_Handler;
  113.    type R_Link is access all Registered_Handler;
  114.  
  115.    type Registered_Handler is record
  116.       H :    Ada.Interrupts.Parameterless_Handler := null;
  117.       Next : R_Link := null;
  118.    end record;
  119.  
  120.    Registered_Handler_Head : R_Link := null;
  121.    Registered_Handler_Tail : R_Link := null;
  122.  
  123.  
  124.    task Handler_Manager is
  125.       entry Bind_Handler       (Interrupt : Ada.Interrupts.Interrupt_ID);
  126.       entry Unbind_Handler     (Interrupt : Ada.Interrupts.Interrupt_ID);
  127.       entry Block_Interrupt    (Interrupt : Ada.Interrupts.Interrupt_ID);
  128.       entry Unblock_Interrupt  (Interrupt : Ada.Interrupts.Interrupt_ID);
  129.       pragma Interrupt_Priority (System.Interrupt_Priority'Last);
  130.    end Handler_Manager;
  131.  
  132.    task type Handler_Task (Interrupt : Ada.Interrupts.Interrupt_ID) is
  133.       pragma Interrupt_Priority (System.Interrupt_Priority'First);
  134.    end Handler_Task;
  135.  
  136.    type Handler_Task_Access is access Handler_Task;
  137.  
  138.    Handler_Access :
  139.      array (Ada.Interrupts.Interrupt_ID'Range) of  Handler_Task_Access
  140.        := (others => null);
  141.  
  142.  
  143.    --  local procedures
  144.  
  145.    ---------------------------
  146.    -- Unmask_All_Interrupts --
  147.    ---------------------------
  148.  
  149.    procedure Unmask_All_Interrupts;
  150.  
  151.    ----------------------------
  152.    -- Thread_Block_Interrupt --
  153.    ----------------------------
  154.  
  155.    procedure Thread_Block_Interrupt (Interrupt : Ada.Interrupts.Interrupt_ID);
  156.  
  157.    ------------------------------
  158.    -- Thread_Unblock_Interrupt --
  159.    ------------------------------
  160.  
  161.    procedure Thread_Unblock_Interrupt
  162.      (Interrupt : Ada.Interrupts.Interrupt_ID);
  163.  
  164.    ----------------------------------
  165.    -- Initialize_Usable_Interrupts --
  166.    ----------------------------------
  167.  
  168.    procedure Initialize_Usable_Interrupts;
  169.  
  170.    --------------------
  171.    -- User_Installed --
  172.    --------------------
  173.  
  174.    --  return true if User_Handler or User_Entry is installed for the Interrupt
  175.    function User_Installed (Interrupt : Ada.Interrupts.Interrupt_ID)
  176.      return Boolean;
  177.  
  178.    -----------------
  179.    -- Signal_Task --
  180.    -----------------
  181.  
  182.    procedure Signal_Task
  183.      (T : System.Tasking.Task_ID; Interrupt : Ada.Interrupts.Interrupt_ID);
  184.  
  185.    ----------------------------------
  186.    -- Unprotected_Exchange_Handler --
  187.    ----------------------------------
  188.  
  189.    procedure Unprotected_Exchange_Handler
  190.      (Old_Handler : out Ada.Interrupts.Parameterless_Handler;
  191.       New_Handler : in Ada.Interrupts.Parameterless_Handler;
  192.       Interrupt   : in Ada.Interrupts.Interrupt_ID;
  193.       Static      : in boolean := false);
  194.  
  195.    -------------------
  196.    -- Is_Registered --
  197.    -------------------
  198.  
  199.    --  See if the Handler has been "pragma"ed using Interrupt_Hanlder.
  200.    --  Always consider a null handler as registered.
  201.  
  202.    function Is_Registered
  203.      (Handler : Ada.Interrupts.Parameterless_Handler) return boolean;
  204.  
  205.    --  end of local procedure declarations.
  206.  
  207.  
  208.    task body Handler_Manager is
  209.       Default_Action : aliased RTE.struct_sigaction;
  210.       Oact           : aliased RTE.struct_sigaction;
  211.       Result         : Interfaces.C.POSIX_Error.Return_Code;
  212.       Error          : Boolean;
  213.    begin
  214.  
  215.       System.Tasking.Utilities.Make_Independent;
  216.  
  217.       Default_Action.sa_handler := Storage_Elements.To_Address (RTE.SIG_DFL);
  218.  
  219.       Unmask_All_Interrupts;
  220.       --  Initially unmask all interrupts so that the default action
  221.       --  is enforced.
  222.  
  223.       --  Notice : When a task is created it inherits its signal mask from the
  224.       --  calling task and all usable interrupts are masked initially.
  225.       --  (cf: Initialize_LL_Tasks, Create_LL_Task, LL_Wrapper in s-taspri.adb)
  226.  
  227.       loop
  228.  
  229.          select
  230.  
  231.          accept Bind_Handler (Interrupt : Ada.Interrupts.Interrupt_ID) do
  232.  
  233.             --  This entry is called only when the Interrupt is Unblocked on
  234.             --  the process level.
  235.  
  236.             Thread_Block_Interrupt (Interrupt);
  237.             --  Mask this task for the given Interrupt so that all tasks
  238.             --  are masked for the Interrupt and the actuall delivery of the
  239.             --  Interrupt will be caught using "sigwait" by the corresponding
  240.             --  Handler_Task.
  241.  
  242.             Cond_Signal (C (Interrupt));
  243.             --  we have installed a Handler or an Entry before we called
  244.             --  this entry. If the Handler Task is waiting to be awakened,
  245.             --  do it here. Otherwise, the signal will be discarded.
  246.  
  247.          end Bind_Handler;
  248.  
  249.          or accept Unbind_Handler (Interrupt : Ada.Interrupts.Interrupt_ID) do
  250.  
  251.             --  This entry is called only when the Interrupt is Unblocked on
  252.             --  the process level.
  253.  
  254.             --  Currently, there is a Handler or an Entry attached and
  255.             --  corresponding Hanlder_Task is waiting on "sigwait."
  256.  
  257.             Signal_Task (Handler_Task_IDs (Interrupt), Interrupt);
  258.             --  We have to wake the Handler_Task up and make it
  259.             --  wait on condition variable.
  260.  
  261.             RTE.sigaction
  262.               (RTE.Signal (Interrupt),
  263.                Default_Action'Access,
  264.                Oact'Access,
  265.                Result);
  266.             pragma Assert (Result /= Failure or else
  267.               Utilities.Runtime_Assert_Shutdown (
  268.                 "Interrupt Failure---sigaction"));
  269.             --  restore the default action in case it is ruined.
  270.  
  271.             Thread_Unblock_Interrupt (Interrupt);
  272.             --  unmake the Interrupt for this task in order to
  273.             --  allow default action again.
  274.  
  275.          end Unbind_Handler;
  276.  
  277.          or accept Block_Interrupt (Interrupt : Ada.Interrupts.Interrupt_ID) do
  278.  
  279.             --  This entry is called only when the Interrupt is Unblocked on
  280.             --  the process level.
  281.  
  282.             Thread_Block_Interrupt (Interrupt);
  283.             --  Mask this task for the given Interrupt so that all tasks
  284.             --  are masked for the Interrupt.
  285.  
  286.             if User_Installed (Interrupt) then
  287.                --  this is the case where the Handler_Task is waiting on
  288.                --  "sigwait." Wake it up and make it wait on Cond.
  289.                Signal_Task (Handler_Task_IDs (Interrupt), Interrupt);
  290.             end if;
  291.  
  292.          end Block_Interrupt;
  293.  
  294.          or accept
  295.            Unblock_Interrupt (Interrupt : Ada.Interrupts.Interrupt_ID) do
  296.  
  297.             --  This entry is called only when the Interrupt is Blocked on
  298.             --  the process level.
  299.  
  300.             if not User_Installed (Interrupt) then
  301.                --  No handler is attached. Unmask the Interrupt so that
  302.                --  the default action can be carried out.
  303.                Thread_Unblock_Interrupt (Interrupt);
  304.             end if;
  305.  
  306.             Cond_Signal (C (Interrupt));
  307.             --  The Handler Task must be waiting on the Cond variable
  308.             --  since it was being blocked. Wake it up and let it change
  309.             --  it place of waiting according to its new state.
  310.             --  If there is no Handler_Task being activated, this signal
  311.             --  will be lost.
  312.  
  313.          end Unblock_Interrupt;
  314.  
  315.          end select;
  316.  
  317.       end loop;
  318.    end Handler_Manager;
  319.  
  320.    task body Handler_Task is
  321.       Sigwait_Mask   : aliased RTE.Signal_Set;
  322.       Sigwait_Signal : RTE.Signal;
  323.       Result         : Interfaces.C.POSIX_Error.Return_Code;
  324.       Error          : Boolean;
  325.    begin
  326.       System.Tasking.Utilities.Make_Independent;
  327.       --  By making this task independent of master, when the process
  328.       --  goes away, the Handler_Task will terminate gracefully.
  329.  
  330.       Handler_Task_IDs (Interrupt) := System.Tasking.Self;
  331.       --  Save the ID of this task so that others can explicitly
  332.       --  send a signal to this task (thread) using Send_Signal (pthread_kill).
  333.  
  334.       RTE.sigemptyset (Sigwait_Mask'Access, Result);
  335.       pragma Assert (Result /= Failure or else
  336.         Utilities.Runtime_Assert_Shutdown ("Interrupt Failure---sigemptyset"));
  337.       RTE.sigaddset (Sigwait_Mask'Access, RTE.Signal (Interrupt), Result);
  338.       pragma Assert (Result /= Failure or else
  339.         Utilities.Runtime_Assert_Shutdown ("Interrupt Failure---sigaddset"));
  340.  
  341.       loop
  342.          if not User_Installed (Interrupt)
  343.             --  No Interrupt binding. If there is an interrupt,
  344.             --  Handler_Manager will take default action.
  345.  
  346.            or else Status_Blocked (Interrupt) then
  347.             --  Interrupt is blocked.
  348.             --  Stay here, so we won't catch the Interrupt.
  349.  
  350.             Write_Lock  (M (Interrupt), Error);
  351.             Cond_Wait  (C (Interrupt), M (Interrupt));
  352.             Unlock (M (Interrupt));
  353.  
  354.          else
  355.             --  A Handler or an Entry is installed. At this point all tasks
  356.             --  mask for the Interrupt is masked. Catch the Signal using
  357.             --  "sigwait."
  358.  
  359.             Interfaces.C.Sthreads.sigwait
  360.                (Sigwait_Mask, Sigwait_Signal, Result);
  361.             pragma Assert (Result /= Failure or else
  362.               Utilities.Runtime_Assert_Shutdown
  363.                 ("Interrupt Failure---sigwait"));
  364.  
  365.             --  This task may wake up from sigwait by receiving a signal
  366.             --  from the Handler_Manager for unbinding a Interrupt Handler or
  367.             --  an Entry. Or it could be a wake up from status change
  368.             --  (Unblocked -> Blocked). If that is not the case, we should
  369.             --  exceute the attached Procedure or Entry.
  370.  
  371.             if Status_Blocked (Interrupt) then
  372.                null;
  373.             elsif User_Handlers (Interrupt) /= Null_Handler_Assoc then
  374.                User_Handlers (Interrupt).H.all;
  375.             elsif User_Entries (Interrupt) /= Null_Entry_Assoc then
  376.                System.Tasking.Rendezvous.Call_Simple
  377.                  (User_Entries (Interrupt).T, User_Entries (Interrupt).E,
  378.                   System.Null_Address);
  379.             end if;
  380.  
  381.          end if;
  382.       end loop;
  383.    end Handler_Task;
  384.  
  385.    -----------------
  386.    -- Is_Reserved --
  387.    -----------------
  388.  
  389.    function Is_Reserved (Interrupt : Ada.Interrupts.Interrupt_ID)
  390.      return Boolean is
  391.    begin
  392.       return not Usable_Interrupts (Interrupt);
  393.    end Is_Reserved;
  394.  
  395.    -----------------
  396.    -- Is_Attached --
  397.    -----------------
  398.  
  399.    function Is_Attached (Interrupt : Ada.Interrupts.Interrupt_ID)
  400.      return Boolean is
  401.       Test  : Boolean;
  402.       Error : Boolean;
  403.    begin
  404.       if Is_Reserved (Interrupt) then
  405.          raise Program_Error;
  406.       end if;
  407.  
  408.       Write_Lock (M (Interrupt), Error);
  409.       Test := User_Handlers (Interrupt) /= Null_Handler_Assoc;
  410.       Unlock (M (Interrupt));
  411.       return Test;
  412.    end Is_Attached;
  413.  
  414.    ---------------------
  415.    -- Current_Handler --
  416.    ---------------------
  417.  
  418.    function Current_Handler (Interrupt : Ada.Interrupts.Interrupt_ID)
  419.      return Ada.Interrupts.Parameterless_Handler is
  420.  
  421.       Handler : Ada.Interrupts.Parameterless_Handler;
  422.       Error   : Boolean;
  423.    begin
  424.       if Is_Reserved (Interrupt) then
  425.          raise Program_Error;
  426.       end if;
  427.  
  428.       Write_Lock (M (Interrupt), Error);
  429.       Handler := User_Handlers (Interrupt).H;
  430.       Unlock (M (Interrupt));
  431.       return Handler;
  432.    end Current_Handler;
  433.  
  434.    --------------------
  435.    -- Attach_Handler --
  436.    --------------------
  437.  
  438.    --  Calling this procedure with New_Handler = null and Static = true
  439.    --  means that we want to Detach the current handler regardless of
  440.    --  the previous handler's binding status (ie. do not care if
  441.    --  it is a dynamic or static handler).
  442.  
  443.    procedure Attach_Handler
  444.      (New_Handler : in Ada.Interrupts.Parameterless_Handler;
  445.       Interrupt   : in Ada.Interrupts.Interrupt_ID;
  446.       Static      : in boolean := false) is
  447.  
  448.       Old_Handler : Ada.Interrupts.Parameterless_Handler;
  449.       Error       : Boolean;
  450.    begin
  451.       if Is_Reserved (Interrupt) then
  452.          raise Program_Error;
  453.       end if;
  454.  
  455.       Write_Lock (M (Interrupt), Error);
  456.  
  457.       --  In case we have an Interrupt Entry already installed,
  458.       --  raise a program error.
  459.       if User_Entries (Interrupt) /= Null_Entry_Assoc then
  460.          Unlock (M (Interrupt));
  461.          raise Program_Error;
  462.       end if;
  463.  
  464.       if not Static and then
  465.         (User_Handlers (Interrupt).Static or else
  466.          --  tries to overwrite a static Interrupt Handler with a
  467.          --  dynamic Handler
  468.          not Is_Registered (New_Handler)) then
  469.          --  The new handler is not specified as an Interrupt
  470.          --  Handler by a pragma.
  471.  
  472.          Unlock (M (Interrupt));
  473.          raise Program_Error;
  474.       end if;
  475.  
  476.       Unprotected_Exchange_Handler
  477.         (Old_Handler, New_Handler, Interrupt, Static);
  478.       Unlock (M (Interrupt));
  479.    end Attach_Handler;
  480.  
  481.    ----------------------
  482.    -- Exchange_Handler --
  483.    ----------------------
  484.  
  485.    --  Calling this procedure with New_Handler = null and Static = true
  486.    --  means that we want to Detach the current handler regardless of
  487.    --  the previous handler's binding status (ie. do not care if
  488.    --  it is a dynamic or static handler).
  489.  
  490.    procedure Exchange_Handler
  491.      (Old_Handler : out Ada.Interrupts.Parameterless_Handler;
  492.       New_Handler : in Ada.Interrupts.Parameterless_Handler;
  493.       Interrupt   : in Ada.Interrupts.Interrupt_ID;
  494.       Static      : in boolean := false) is
  495.  
  496.       Error : Boolean;
  497.    begin
  498.       if Is_Reserved (Interrupt) then
  499.          raise Program_Error;
  500.       end if;
  501.  
  502.       Write_Lock (M (Interrupt), Error);
  503.  
  504.       --  In case we have an Interrupt Entry already installed,
  505.       --  raise a program error.
  506.       if User_Entries (Interrupt) /= Null_Entry_Assoc then
  507.          Unlock (M (Interrupt));
  508.          raise Program_Error;
  509.       end if;
  510.  
  511.       if not Static and then
  512.         (User_Handlers (Interrupt).Static or else
  513.          --  tries to overwrite a static Interrupt Handler with a
  514.          --  dynamic Handler
  515.          not Is_Registered (New_Handler)) then
  516.          --  The new handler is not specified as an Interrupt
  517.          --  Handler by a pragma.
  518.  
  519.          Unlock (M (Interrupt));
  520.          raise Program_Error;
  521.       end if;
  522.  
  523.       Unprotected_Exchange_Handler
  524.         (Old_Handler, New_Handler, Interrupt, Static);
  525.       Unlock (M (Interrupt));
  526.    end Exchange_Handler;
  527.  
  528.    ----------------------------------
  529.    -- Unprotected_Exchange_Handler --
  530.    ----------------------------------
  531.  
  532.    procedure Unprotected_Exchange_Handler
  533.      (Old_Handler : out Ada.Interrupts.Parameterless_Handler;
  534.       New_Handler : in Ada.Interrupts.Parameterless_Handler;
  535.       Interrupt   : in Ada.Interrupts.Interrupt_ID;
  536.       Static      : in boolean := false) is
  537.    begin
  538.  
  539.       --  Save the old handler
  540.       Old_Handler := User_Handlers (Interrupt).H;
  541.  
  542.       --  The new handler
  543.       User_Handlers (Interrupt).H := New_Handler;
  544.  
  545.       --  Consider null handler dynamic regardless of Static information.
  546.       if New_Handler = null then
  547.          User_Handlers (Interrupt).Static := false;
  548.       else
  549.          User_Handlers (Interrupt).Static := Static;
  550.       end if;
  551.  
  552.       if Handler_Access (Interrupt) = null then
  553.          --  if the Handler_Task is not yet created, do it now.
  554.          Handler_Access (Interrupt) := new Handler_Task (Interrupt);
  555.       end if;
  556.  
  557.       if Status_Blocked (Interrupt) then
  558.          --  if the signal is currently blocked,
  559.          --  no further operations are needed.
  560.          return;
  561.       end if;
  562.  
  563.       if (New_Handler = null) then
  564.          if Old_Handler /= null then
  565.             Handler_Manager.Unbind_Handler (Interrupt);
  566.          end if;
  567.          return;
  568.       end if;
  569.  
  570.       if Old_Handler = null then
  571.          Handler_Manager.Bind_Handler (Interrupt);
  572.       end if;
  573.  
  574.    end Unprotected_Exchange_Handler;
  575.  
  576.    --------------------
  577.    -- Detach_Handler --
  578.    --------------------
  579.  
  580.    --  Calling this procedure with Static = true
  581.    --  means that we want to Detach the current handler regardless of
  582.    --  the previous handler's binding status (ie. do not care if
  583.    --  it is a dynamic or static handler).
  584.  
  585.    procedure Detach_Handler
  586.      (Interrupt : in Ada.Interrupts.Interrupt_ID;
  587.       Static    : in boolean := false) is
  588.       Old_Handler : Ada.Interrupts.Parameterless_Handler;
  589.       Error : Boolean;
  590.    begin
  591.       if Is_Reserved (Interrupt) then
  592.          raise Program_Error;
  593.       end if;
  594.  
  595.       Write_Lock (M (Interrupt), Error);
  596.  
  597.       --  In case we have an Interrupt Entry already installed,
  598.       --  raise a program error.
  599.       if User_Entries (Interrupt) /= Null_Entry_Assoc then
  600.          Unlock (M (Interrupt));
  601.          raise Program_Error;
  602.       end if;
  603.  
  604.       if not Static and then User_Handlers (Interrupt).Static then
  605.          --  tries to detach a static Interrupt Handler.
  606.  
  607.          Unlock (M (Interrupt));
  608.          raise Program_Error;
  609.       end if;
  610.  
  611.       Unprotected_Exchange_Handler (Old_Handler, null, Interrupt);
  612.       Unlock (M (Interrupt));
  613.    end Detach_Handler;
  614.  
  615.    ---------------
  616.    -- Reference --
  617.    ---------------
  618.  
  619.    function Reference (Interrupt : Ada.Interrupts.Interrupt_ID)
  620.      return System.Address is
  621.       Signal : System.Address :=
  622.         System.Storage_Elements.To_Address
  623.           (System.Storage_Elements.Integer_Address (Interrupt));
  624.    begin
  625.       if Is_Reserved (Interrupt) then
  626.       --  Only usable Interrupts can be used for binding it to an Entry.
  627.          raise Program_Error;
  628.       end if;
  629.       return Signal;
  630.    end Reference;
  631.  
  632.    ----------------------------------
  633.    --  Register_Interrupt_Handler  --
  634.    ----------------------------------
  635.  
  636.    procedure Register_Interrupt_Handler
  637.      (Handler : Ada.Interrupts.Parameterless_Handler) is
  638.       New_Node_Ptr : R_Link;
  639.       Ptr  : R_Link;
  640.    begin
  641.       --  This routine registers the Handler as usable for Dynamic
  642.       --  Interrupt Handler. Routines attaching and detaching Handler
  643.       --  dynamically should first consult if the Handler is rgistered.
  644.       --  A Program Error should be raised if it is not registered.
  645.  
  646.       --  The pragma Interrupt_Handler can only appear in the library
  647.       --  level PO definition and instantiation. Therefore, we do not need
  648.       --  to implement Unregistering operation. Neither we need to
  649.       --  protect the queue structure using a Write Lock.
  650.  
  651.       pragma Assert (Handler /= null or else
  652.         Utilities.Runtime_Assert_Shutdown (
  653.           "Interrupt Failure---a null handler should not be registered"));
  654.  
  655.       New_Node_Ptr := new Registered_Handler;
  656.       New_Node_Ptr.H := Handler;
  657.  
  658.       if Registered_Handler_Head = null then
  659.          Registered_Handler_Head := New_Node_Ptr;
  660.          Registered_Handler_Tail := New_Node_Ptr;
  661.       else
  662.          Registered_Handler_Tail.Next := New_Node_Ptr;
  663.          Registered_Handler_Tail := New_Node_Ptr;
  664.       end if;
  665.  
  666.    end Register_Interrupt_Handler;
  667.  
  668.    function Is_Registered
  669.      (Handler : Ada.Interrupts.Parameterless_Handler) return boolean is
  670.       Ptr : R_Link;
  671.    begin
  672.       if Handler = null then
  673.          return true;
  674.       end if;
  675.  
  676.       Ptr := Registered_Handler_Head;
  677.  
  678.       while (Ptr /= null) loop
  679.          if Ptr.H = Handler then
  680.             return true;
  681.          end if;
  682.          Ptr := Ptr.Next;
  683.       end loop;
  684.       return false;
  685.  
  686.    end Is_Registered;
  687.  
  688.    ---------------------------
  689.    -- Unmask_All_Interrupts --
  690.    ---------------------------
  691.  
  692.    --  Unmask all usable interrupts for calling task (thread).
  693.  
  694.    procedure Unmask_All_Interrupts is
  695.       Signal_Mask, Old_Set : aliased RTE.Signal_Set;
  696.       Result : Interfaces.C.POSIX_Error.Return_Code;
  697.    begin
  698.       RTE.sigfillset (Signal_Mask'Access, Result);
  699.       pragma Assert (Result /= Failure or else
  700.         Utilities.Runtime_Assert_Shutdown ("Interrupt Failure---sigfillset"));
  701.  
  702.       Interfaces.C.Sthreads.thr_sigsetmask (
  703.         RTE.SIG_UNBLOCK, Signal_Mask'Access, Old_Set'Access, Result);
  704.       pragma Assert (Result /= Failure or else
  705.         Utilities.Runtime_Assert_Shutdown (
  706.           "Interrupt Failure---thr_sigsetmask"));
  707.    end Unmask_All_Interrupts;
  708.  
  709.    ----------------------------
  710.    -- Thread_Block_Interrupt --
  711.    ----------------------------
  712.  
  713.    procedure Thread_Block_Interrupt
  714.      (Interrupt : Ada.Interrupts.Interrupt_ID) is
  715.       Signal_Mask, Old_Set : aliased RTE.Signal_Set;
  716.       Result : Interfaces.C.POSIX_Error.Return_Code;
  717.    begin
  718.       RTE.sigemptyset (Signal_Mask'Access, Result);
  719.       pragma Assert (Result /= Failure or else
  720.         Utilities.Runtime_Assert_Shutdown ("Interrupt Failure---sigemptyset"));
  721.       RTE.sigaddset (Signal_Mask'Access, RTE.Signal (Interrupt), Result);
  722.       pragma Assert (Result /= Failure or else
  723.         Utilities.Runtime_Assert_Shutdown ("Interrupt Failure---sigaddset"));
  724.       Interfaces.C.Sthreads.thr_sigsetmask (
  725.         RTE.SIG_BLOCK, Signal_Mask'Access, Old_Set'Access, Result);
  726.       pragma Assert (Result /= Failure or else
  727.         Utilities.Runtime_Assert_Shutdown (
  728.           "Interrupt Failure---thr_sigsetmask"));
  729.    end Thread_Block_Interrupt;
  730.  
  731.    ------------------------------
  732.    -- Thread_Unblock_Interrupt --
  733.    ------------------------------
  734.  
  735.    procedure Thread_Unblock_Interrupt
  736.      (Interrupt : Ada.Interrupts.Interrupt_ID) is
  737.       Signal_Mask, Old_Set : aliased RTE.Signal_Set;
  738.       Result : Interfaces.C.POSIX_Error.Return_Code;
  739.    begin
  740.       RTE.sigemptyset (Signal_Mask'Access, Result);
  741.       pragma Assert (Result /= Failure or else
  742.         Utilities.Runtime_Assert_Shutdown ("Interrupt Failure---sigemptyset"));
  743.       RTE.sigaddset (Signal_Mask'Access, RTE.Signal (Interrupt), Result);
  744.       pragma Assert (Result /= Failure or else
  745.         Utilities.Runtime_Assert_Shutdown ("Interrupt Failure---sigaddset"));
  746.       Interfaces.C.Sthreads.thr_sigsetmask (
  747.         RTE.SIG_UNBLOCK, Signal_Mask'Access, Old_Set'Access, Result);
  748.       pragma Assert (Result /= Failure or else
  749.         Utilities.Runtime_Assert_Shutdown (
  750.           "Interrupt Failure---thr_sigsetmask"));
  751.    end Thread_Unblock_Interrupt;
  752.  
  753.    --------------------
  754.    -- User_Installed --
  755.    --------------------
  756.  
  757.    function User_Installed (Interrupt : Ada.Interrupts.Interrupt_ID)
  758.      return Boolean is
  759.    begin
  760.       return
  761.         User_Handlers (Interrupt) /= Null_Handler_Assoc or else
  762.           User_Entries (Interrupt) /= Null_Entry_Assoc;
  763.    end User_Installed;
  764.  
  765.    -------------------
  766.    --  Signal_Task  --
  767.    -------------------
  768.  
  769.    procedure Signal_Task
  770.      (T : System.Tasking.Task_ID;
  771.       Interrupt : Ada.Interrupts.Interrupt_ID) is
  772.  
  773.       type ATCB_Ptr is access Tasking.Ada_Task_Control_Block;
  774.  
  775.       function Task_ID_To_ATCB_Ptr is new
  776.         Unchecked_Conversion (Tasking.Task_ID, ATCB_Ptr);
  777.  
  778.       T_Access : Task_Primitives.TCB_Ptr :=
  779.         Task_ID_To_ATCB_Ptr (T).LL_TCB'Unchecked_Access;
  780.       Result : Interfaces.C.POSIX_Error.Return_Code;
  781.    begin
  782.       Interfaces.C.Sthreads.thr_kill
  783.          (T_Access.Thread, RTE.Signal (Interrupt), Result);
  784.       pragma Assert (Result /= Failure or else
  785.         Utilities.Runtime_Assert_Shutdown (
  786.           "Interrupt Failure---thr_kill"));
  787.    end Signal_Task;
  788.  
  789.    -----------------------------
  790.    -- Bind_Interrupt_To_Entry --
  791.    -----------------------------
  792.  
  793.    --  This procedure raises a Program_Error if it tries to
  794.    --  bind an interrupt to which an Interrupt Entry or a Protected
  795.    --  Procedure is already bound.
  796.  
  797.    procedure Bind_Interrupt_To_Entry
  798.      (T       : System.Tasking.Task_ID;
  799.       E       : System.Tasking.Task_Entry_Index;
  800.       Int_Ref : System.Address) is
  801.  
  802.       Interrupt :
  803.         Ada.Interrupts.Interrupt_ID :=
  804.           Ada.Interrupts.Interrupt_ID
  805.             (System.Storage_Elements.To_Integer (Int_Ref));
  806.       Error : Boolean;
  807.    begin
  808.       if Is_Reserved (Interrupt) then
  809.          raise Program_Error;
  810.       end if;
  811.  
  812.       Write_Lock (M (Interrupt), Error);
  813.  
  814.       --  if there is a binding already (either a Procedure or an Entry),
  815.       --  raise Program_Error.
  816.       if User_Installed (Interrupt) then
  817.          Unlock (M (Interrupt));
  818.          raise Program_Error;
  819.       end if;
  820.  
  821.       User_Entries (Interrupt) := Entry_Assoc' (T => T, E => E);
  822.  
  823.       --  Indicate the attachment of Interrupt Entry in ATCB.
  824.       T.Interrupt_Entry := true;
  825.  
  826.       if Handler_Access (Interrupt) = null then
  827.          Handler_Access (Interrupt) := new Handler_Task (Interrupt);
  828.          --  Invoke the corresponding Handler_Task
  829.       end if;
  830.  
  831.       if not Status_Blocked (Interrupt) then
  832.          Handler_Manager.Bind_Handler (Interrupt);
  833.       end if;
  834.  
  835.       Unlock (M (Interrupt));
  836.  
  837.    end Bind_Interrupt_To_Entry;
  838.  
  839.    ------------------------------
  840.    -- Detach_Interrupt_Entries --
  841.    ------------------------------
  842.  
  843.    procedure Detach_Interrupt_Entries (T : Tasking.Task_ID) is
  844.       Error : Boolean;
  845.    begin
  846.       for I in Ada.Interrupts.Interrupt_ID'Range loop
  847.          if not Is_Reserved (I) then
  848.             Write_Lock (M (I), Error);
  849.             if User_Entries (I) /= Null_Entry_Assoc and then
  850.               User_Entries (I).T = T then
  851.                User_Entries (I) := Null_Entry_Assoc;
  852.                if not Status_Blocked (I) then
  853.                   Handler_Manager.Unbind_Handler (I);
  854.                end if;
  855.             end if;
  856.             Unlock (M (I));
  857.          end if;
  858.       end loop;
  859.  
  860.       --  Indicate in ATCB that no Interrupt Entries are attached.
  861.       T.Interrupt_Entry := false;
  862.  
  863.    end Detach_Interrupt_Entries;
  864.  
  865.    ---------------------
  866.    -- Block_Interrupt --
  867.    ---------------------
  868.  
  869.    procedure Block_Interrupt (Interrupt : Ada.Interrupts.Interrupt_ID) is
  870.       Error : Boolean;
  871.    begin
  872.       if Is_Reserved (Interrupt) then
  873.          raise Program_Error;
  874.       end if;
  875.  
  876.       if Is_Blocked (Interrupt) then
  877.          return;
  878.       end if;
  879.  
  880.       Write_Lock (M (Interrupt), Error);
  881.       Status_Blocked (Interrupt) := true;
  882.       Handler_Manager.Block_Interrupt (Interrupt);
  883.       Unlock (M (Interrupt));
  884.  
  885.    end Block_Interrupt;
  886.  
  887.    -----------------------
  888.    -- Unblock_Interrupt --
  889.    -----------------------
  890.  
  891.    procedure Unblock_Interrupt (Interrupt : Ada.Interrupts.Interrupt_ID) is
  892.       Error : Boolean;
  893.    begin
  894.       if Is_Reserved (Interrupt) then
  895.          raise Program_Error;
  896.       end if;
  897.  
  898.       if not Is_Blocked (Interrupt) then
  899.          return;
  900.       end if;
  901.  
  902.       Write_Lock (M (Interrupt), Error);
  903.       Status_Blocked (Interrupt) := false;
  904.       Handler_Manager.Unblock_Interrupt (Interrupt);
  905.       Unlock (M (Interrupt));
  906.  
  907.    end Unblock_Interrupt;
  908.  
  909.    ----------------
  910.    -- Is_Blocked --
  911.    ----------------
  912.  
  913.    function Is_Blocked (Interrupt : Ada.Interrupts.Interrupt_ID)
  914.      return boolean is
  915.       Error : Boolean;
  916.       Tmp   : Boolean;
  917.    begin
  918.       if Is_Reserved (Interrupt) then
  919.          raise Program_Error;
  920.       end if;
  921.  
  922.       Write_Lock (M (Interrupt), Error);
  923.       Tmp := Status_Blocked (Interrupt);
  924.       Unlock (M (Interrupt));
  925.  
  926.       return Tmp;
  927.    end Is_Blocked;
  928.  
  929.    ----------------------------------
  930.    -- Initialize_Usable_Interrupts --
  931.    ----------------------------------
  932.  
  933.  
  934.    --  Only those interrupts classified as Asynchronous Signals in RTE
  935.    --  can be used by users.
  936.  
  937.    procedure Initialize_Usable_Interrupts is
  938.    begin
  939.       Usable_Interrupts :=
  940.         (SIGHUP | SIGQUIT | SIGPIPE | SIGTERM | SIGUSR2 |
  941.          SIGSYS | SIGPOLL | SIGVTALRM | SIGPROF | SIGXCPU | SIGXFSZ => true,
  942.          others => false);
  943.  
  944.    --  SIGCONT     : constant Interrupt_ID := 25;
  945.    --  SIGTSTP     : constant Interrupt_ID := 24;
  946.    --  SIGTTIN     : constant Interrupt_ID := 26;
  947.    --  SIGTTOU     : constant Interrupt_ID := 27;
  948.    --  SIGWINCH    : constant Interrupt_ID := 20;
  949.    --  SIGURG      : constant Interrupt_ID := 21;
  950.    end Initialize_Usable_Interrupts;
  951.  
  952. begin
  953.    Initialize_Usable_Interrupts;
  954. end System.Interrupts;
  955.